//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "csharedmemory.h"
#include "helper.h"
#include <aura.h>

CSharedMemory::~CSharedMemory()
{
    if (NULL != m_hSharedMemory) {
        AuraSharedMemory_Destroy(m_hSharedMemory);
        m_hSharedMemory = NULL;
    }

    if (NULL != m_hLock) {
        AuraCriticalSection_Destroy(m_hLock);
        m_hLock = NULL;
    }
}

ECode CSharedMemory::Constructor(
        /* [in] */ WString name,
        /* [in] */ MemorySize memorySize,
        /* [in] */ Boolean bCommit,
        /* [out] */ Boolean * pbAlreadyExisted)
{
    assert(!name.IsNullOrEmpty());
    assert(NULL != pbAlreadyExisted);

    ECode ec = NOERROR;

    ec = AuraCriticalSection_Create(&m_hLock);
    if (FAILED(ec)) {
        goto E_FAIL_EXIT;
    }
    ec = AuraSharedMemory_Create((Aura_PWChar)(const wchar_t *)name,
                             memorySize,
                             bCommit,
                             &m_hSharedMemory,
                             (Aura_Bool*)pbAlreadyExisted);
    if (FAILED(ec)) {
        goto E_FAIL_EXIT;
    }

    return ec;

E_FAIL_EXIT:
    if (NULL != m_hLock) {
        AuraCriticalSection_Destroy(m_hLock);
        m_hLock = NULL;
    }
    return ec;
}

PInterface CSharedMemory::Probe(
        /* [in]  */ REIID riid)
{
    if (riid == EIID_IInterface) {
        return (PInterface)(ISharedMemory *)this;
    }
    else if (riid == EIID_ISharedMemory) {
        return (ISharedMemory *)this;
    }
    else if (riid == EIID_CLASS_INFO) {
        return (PInterface)&ECLSID_CSharedMemory;
    }
    else if (riid == EIID_INTERFACE_INFO) {
        return (PInterface)&EIID_ISharedMemory;
    }

    return NULL;
}

UInt32 CSharedMemory::AddRef()
{
    Int32 nRefs = m_cRefs.Increment();

    return (UInt32)nRefs;
}

UInt32 CSharedMemory::Release()
{
    Int32 nRefs = m_cRefs.Decrement();
    if (0 == nRefs) {
        delete this;
    }
    return (UInt32)nRefs;
}

ECode CSharedMemory::Aggregate(
        /* [in]  */ AggregateType type,
        /* [in]  */ PInterface pObject)
{
    return E_NOT_IMPLEMENTED;
}

ECode CSharedMemory::GetDomain(
        /* [out] */ PInterface * ppObj)
{
    return E_NOT_IMPLEMENTED;
}

ECode CSharedMemory::Attach(
        /* [in]  */ MemoryProtection protect,
        /* [out] */ Address * pAddress)
{
    ECode ec = NOERROR;

    if (NULL == pAddress) {
        return E_INVALID_ARGUMENT;
    }

    LOCK;
    if (m_attachTimes > 0) {
        goto E_NORMAL_EXIT;
    }

    ec = AuraSharedMemory_Attach(m_hSharedMemory,
                             protect,
                            (Aura_Address *)&m_address);
    if (FAILED(ec)) {
        goto E_FAIL_EXIT;
    }

E_NORMAL_EXIT:
    m_attachTimes++;
    UNLOCK;

    *pAddress = m_address;
    return NOERROR;

E_FAIL_EXIT:
    UNLOCK;
    return ec;
}

ECode CSharedMemory::Detach()
{
    ECode ec = NOERROR;

    LOCK;
    switch (m_attachTimes) {
    case 0:
        ec = E_INVALID_OPERATION;
        break;
    case 1:
        ec = AuraSharedMemory_Detach(m_hSharedMemory, m_address);
        if (FAILED(ec)) {
            break;
        }
        m_attachTimes--;
        break;
    default:
        assert(m_attachTimes > 1);
        m_attachTimes--;
        break;
    }
    UNLOCK;

    return ec;
}

ECode CSharedMemory::New(
    /* [in] */ WString name,
    /* [in] */ MemorySize memorySize,
    /* [in] */ Boolean bCommit,
    /* [out] */ ISharedMemory ** ppSharedMemory,
    /* [out] */ Boolean * pbAlreadyExisted)
{
    CSharedMemory * pSharedMemory = NULL;
    ECode ec = NOERROR;

    assert(!name.IsNullOrEmpty());
    assert(NULL != pbAlreadyExisted);
    assert(NULL != ppSharedMemory);

    pSharedMemory = new CSharedMemory();
    if (NULL == pSharedMemory) {
        ec = E_OUT_OF_MEMORY;
        goto E_FAIL_EXIT;
    }
    ec = pSharedMemory->Constructor(name,
                               memorySize,
                               bCommit,
                               pbAlreadyExisted);
    if (FAILED(ec)) {
        goto E_FAIL_EXIT;
    }
    *ppSharedMemory = static_cast<ISharedMemory *>(pSharedMemory);
    (*ppSharedMemory)->AddRef();

    return NOERROR;

E_FAIL_EXIT:
    if (NULL != pSharedMemory) {
        delete pSharedMemory;
    }
    return ec;
}

